package ltd.hxya.novel.crawl.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ltd.hxya.novel.common.bean.Result;
import ltd.hxya.novel.common.bean.ResultEnum;
import ltd.hxya.novel.common.constant.redis.RedisConstant;
import ltd.hxya.novel.common.exception.NovelGlobalException;
import ltd.hxya.novel.common.to.book.BookTo;
import ltd.hxya.novel.common.utils.RedisUtils;
import ltd.hxya.novel.crawl.bean.CrawlVo;
import ltd.hxya.novel.crawl.entity.CrawlRule;
import ltd.hxya.novel.crawl.entity.CrawlSource;
import ltd.hxya.novel.crawl.feign.BookFeignService;
import ltd.hxya.novel.crawl.mapper.CrawlSourceMapper;
import ltd.hxya.novel.crawl.service.ICrawlRuleService;
import ltd.hxya.novel.crawl.service.ICrawlSourceService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 爬虫源表 服务实现类
 * </p>
 *
 * @author hxya
 * @since 2022-09-18
 */
@Service
public class CrawlSourceServiceImpl extends ServiceImpl<CrawlSourceMapper, CrawlSource> implements ICrawlSourceService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private CrawlSourceMapper crawlSourceMapper;

    @Autowired
    private BookFeignService bookFeignService;

    @Autowired
    private ICrawlRuleService crawlRuleService;


    @Override
    public CrawlVo defaultCrawlSource() {
        //查询出爬虫源，并将爬虫源信息封装
        String json = redisUtils.get(RedisConstant.DEFAULT_CRAWL_KEY);
        CrawlVo crawlVo =null;
        if (StringUtils.isEmpty(json)){
            QueryWrapper<CrawlSource> crawlSourceQueryWrapper = new QueryWrapper<>();
            crawlSourceQueryWrapper.eq("source_status",true);
            crawlVo = crawlSourceMapper.defaultCrawlSource();
            //添加到Redis中
            redisUtils.save(RedisConstant.DEFAULT_CRAWL_KEY,crawlVo);
        }else {
            //将从redis中查询到的信息封装
            crawlVo = JSON.parseObject(json, new TypeReference<CrawlVo>() {
            });
        }
        return crawlVo;
    }

    @Override
    public CrawlVo getCrawlSourceById(Integer crawlSourceId) {
        String json = redisUtils.get(RedisConstant.CRAWL_KEY+crawlSourceId.toString());
        CrawlVo crawlVo =null;
        if (StringUtils.isEmpty(json)){
            crawlVo = crawlSourceMapper.getById(crawlSourceId);
            redisUtils.save(RedisConstant.CRAWL_KEY+crawlSourceId,crawlVo);
            return crawlVo;
        }
        crawlVo = JSON.parseObject(json, CrawlVo.class);
        if (ObjectUtils.isEmpty(crawlVo)){
            crawlVo = new CrawlVo();
            CrawlSource crawlSource = getById(crawlSourceId);
            BeanUtils.copyProperties(crawlSource,crawlVo);
        }
        return crawlVo;
    }

    @Override
    public List<CrawlVo> crawlSourceList() {
        List<CrawlVo> crawlVoList =crawlSourceMapper.crawlList();
        return crawlVoList;
    }

    @Transactional
    @Override
    public void updateDefaultCrawlSource(CrawlSource crawlSource) {
        UpdateWrapper<CrawlSource> crawlSourceUpdateWrapper = new UpdateWrapper<>();
        crawlSourceUpdateWrapper.eq("source_status",true);
        this.update(crawlSource,crawlSourceUpdateWrapper);

    }

    @Override
    public void changeCrawlStatus(CrawlSource crawlSource) {
        this.updateById(crawlSource);
        if (crawlSource.getSourceStatus()) {
            UpdateWrapper<CrawlSource> crawlSourceUpdateWrapper = new UpdateWrapper<>();
            crawlSourceUpdateWrapper.ne("id", crawlSource.getId()).set("source_status", false);
            //更新redis的信息
            QueryWrapper<CrawlRule> crawlRuleQueryWrapper = new QueryWrapper<>();
            crawlRuleQueryWrapper.eq("source_id",crawlSource.getId());
            CrawlVo crawlVo = defaultCrawlSource();
            redisUtils.save(RedisConstant.DEFAULT_CRAWL_KEY,crawlVo);
            this.update(crawlSourceUpdateWrapper);
        }
    }

    @Override
    public void addCrawlSource(CrawlSource crawlSource) {
        //判断爬虫源是否存在，如果存在，返回错误消息，如果不存在，添加爬虫源
        checkIsExist(crawlSource);
        crawlSource.setCreateTime(LocalDateTime.now());
        crawlSource.setUpdateTime(LocalDateTime.now());
        save(crawlSource);
    }

    private void checkIsExist(CrawlSource crawlSource) {
        QueryWrapper<CrawlSource> crawlSourceQueryWrapper = new QueryWrapper<>();
        crawlSourceQueryWrapper.eq("source_name", crawlSource.getSourceName());
        CrawlSource crawlSource1 = baseMapper.selectOne(crawlSourceQueryWrapper);
        if (!ObjectUtils.isEmpty(crawlSource1)){
            throw new NovelGlobalException(ResultEnum.CRAWL_SOURCE_EXIST.getCode(), ResultEnum.CRAWL_SOURCE_EXIST.getMsg());
        }
    }

    @Override
    public void deleteCrawlSource(Integer[] ids) {
        if (ids.length<=0||ids==null){
            throw new NovelGlobalException(ResultEnum.PARAM_VALID_FAIL.getCode(), ResultEnum.PARAM_VALID_FAIL.getMsg());
        }
        baseMapper.deleteBatchIds(Arrays.asList(ids));
    }

    @Override
    public void updateCrawlSource(CrawlSource crawlSource) {
        checkIsExist(crawlSource);
        crawlSource.setUpdateTime(LocalDateTime.now());
        updateById(crawlSource);
    }

    @Override
    public CrawlVo crawlSourceByBookId(String bookId) {
        //远程调用查询book信息，并从中取出crawlSourceId
        BookTo bookTo = bookById(bookId);
        Integer crawlSourceId = bookTo.getCrawlSourceId();
        String crawlBookId = bookTo.getCrawlBookId();

        CrawlVo crawlVo = getCrawlSourceById(crawlSourceId);
        Map<String, Object> crawlBookIdMap = new LinkedHashMap<>();
        crawlBookIdMap.put(bookId,crawlBookId);
        crawlVo.setParams(crawlBookIdMap);

        return crawlVo;
    }

    public BookTo bookById(String bookId){
        Result<BookTo> bookResult = bookFeignService.bookInfoById(bookId);
        BookTo bookTo = bookResult.getData();
        return bookTo;
    }
}
